package mm.util;

import java.io.IOException;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

public class Pusher {
	
	private static final String DEFAULT_CONTENT_TYPE="text/plain";

	private ServletOutputStream out;
	private MultipartResponse multi;
	
	private Integer index;
	
	private UploadStats uploadStats;
	
	public Pusher(HttpServletResponse res) throws IOException{
		out = res.getOutputStream();
		multi = new MultipartResponse(res);
	}
	
	public void push(String in){
		push(in, null);
	}
	
	public void push(String in, String contentType){
		checkAvailability();
		if(contentType==null)
			contentType=DEFAULT_CONTENT_TYPE;
		try {
			multi.startResponse(contentType);
			out.print(in);
			multi.endResponse();
		} catch (IOException e) {
			LOG.error("Errors happened in pushing: ", e);
			throw new RuntimeException("Errors happened in pushing: "+e);
		}
	}
	
	public void done(){
		checkAvailability();
		this.setId(null);
		try {
			multi.finish();
		} catch (IOException e) {
			LOG.error("Errors happened in close pushing: ", e);
			throw new RuntimeException("Errors happened in close pushing: "+e);
		}
	}
	
	public void error(Throwable t){
		checkAvailability();
		try {
			multi.startResponse("text/plain"); // TODO need close last response?
			out.print("err:"+t.getMessage()); // FIXME
			multi.endResponse();
//			multi.finish();
		} catch (IOException e) {
			LOG.error("Errors happened in pushing error: ", e);
			throw new RuntimeException("Errors happened in pushing error: "+e); // TODO Can this close the socket?
		}
	}
	
	private void checkAvailability() {
		if(!isAvailable()){
			// stopped
			throw new PusherStoppedException();
		}
	}
	
	public boolean isAvailable() {
		return (this.getId()!=null);
	}

	public void pushId() {
		checkAvailability();
		this.push(index.toString());
	}

	public Integer getId() {
		return index;
	}

	public void setId(Integer index) {
		this.index = index;
	}

	public UploadStats getUploadStats() {
		return uploadStats;
	}

	public void setUploadStats(UploadStats uploadStats) {
		this.uploadStats = uploadStats;
	}

}

class MultipartResponse {

	HttpServletResponse res;
	ServletOutputStream out;
	boolean endedLastResponse = true;

	public MultipartResponse(HttpServletResponse response) throws IOException {
		// Save the response object and output stream
		res = response;
		out = res.getOutputStream();

		// Set things up
		res.setContentType("multipart/x-mixed-replace;boundary=End");
		out.println();
		out.println("--End");
	}

	public void startResponse(String contentType) throws IOException {
		// End the last response if necessary
		if (!endedLastResponse) {
			endResponse();
		}
		// Start the next one
		out.println("Content-Type: " + contentType);
		out.println();
		endedLastResponse = false;
	}

	public void endResponse() throws IOException {
		// End the last response, and flush so the client sees the content
		out.println();
		out.println("--End");
		out.flush();
		endedLastResponse = true;
	}

	public void finish() throws IOException {
		// may cause incomplete output?
		///if (!endedLastResponse) { // TODO necessary?
		///	endResponse();
		///}
		out.println("--End--");
		out.flush();
	}

}
